%:- use_module('abc_rewriter_resourcebounds.yap').
:- use_module('concrete.yap').
:- use_module('clpcheck.yap').

get_method3(MC, [M | _], M) :-
	M =.. [method_body,MC,_MS1,_LC1,_ISD1,_MSD1,_CL1,_NInsList,_EC1,_E1,_TC1,_T1].
get_method3(MC, [M | MT], MF) :-
	get_method3(MC, MT, MF).

get_marked_method2(MC, [(MC-M) | _], M).
get_marked_method2(MC, [M | MT], MF) :-
	get_marked_method2(MC, MT, MF).


%still am not doing the OldState/NewState correctly.
hint_original_seek(path_info(MethodNum,InstrCount,Path),NewPathInfo,WAST) :-

	abc_parser:getABC(method_bodies,WAST,UMethodBodies),
 	get_method3(MethodNum,UMethodBodies,OMETH),
	OMETH =.. [method_body,_Method1,_MS1,_LC1,_ISD1,_MSD1,_CL1,OInsList,_EC1,_E1,_TC1,_T1],
	chop_list_until_nth(OInsList,InstrCount,[_O-I|_IList]),
	
	get_head_args(I,H,ArgList),
	(is_non_sequential(H) -> 
		
		((H \= lookupswitch) ->
			(ArgList = [Offset],
			seek_jump_path(path_info(MethodNum,InstrCount,Path),NewPathInfo,Offset,OMETH))
		;
			writeln('shipoopya'),
			ArgList = [DefaultOffset, CaseCount, CaseOffsets],
			((Path = 0) ->
				Offset = DefaultOffset
			;
				nth(Path, CaseOffsets, Offset)
			),
			NextIC is InstrCount,
			seek_jump_target(Offset, NextIC, OInsList, NextIC, NIC),
			NewPathInfo =.. [path_info, MethodNum, NIC, 0]

		)
	;
		seek_path_once(path_info(MethodNum,InstrCount,Path),NewPathInfo)
	).

hint_rewritten_seek(path_info(MethodNum,InstrCount,Path),NewPathInfo,RMETH,MarkedList,OldLength,RLENGTH) :-

	RMETH =.. [method_body,_Method1,_MS1,_LC1,_ISD1,_MSD1,_CL1,RInsList,_EC1,_E1,_TC1,_T1],
	chop_list_until_nth(RInsList,InstrCount,[O-I|IList]),
	
	
 	nth0(InstrCount, MarkedList, (_MO-_MI,Marking)),

	((Marking = 'Unmarked') -> 
		writeln('Unmarked Instruction'),
		get_head_args(I,H,ArgList),
		(is_non_sequential(H) -> 
			((H \= lookupswitch) ->
				ArgList = [Offset],
				seek_jump_path(path_info(MethodNum,InstrCount,Path),NewPathInfo,Offset,RMETH)
			;
				writeln('shipoopya'),
				ArgList = [DefaultOffset, CaseCount, CaseOffsets],
				((Path = 0) ->
					Offset = DefaultOffset
				;
					nth(Path, CaseOffsets, Offset)
				),
				NextIC is InstrCount,
				seek_jump_target(Offset, NextIC, RInsList, NextIC, NIC),
				NewPathInfo =.. [path_info, MethodNum, NIC, 0]

			)
		;
			seek_path_once(path_info(MethodNum,InstrCount,Path),NewPathInfo)
		),
		RLENGTH is OldLength + 1
	;
		writeln('Marked Instruction'),
		get_head_args(I,H,ArgList),
		(is_non_sequential(H) -> 
			((H \= lookupswitch) ->
				ArgList = [Offset],
				seek_jump_path(path_info(MethodNum,InstrCount,Path),TempPathInfo,Offset,RMETH)
			;
				writeln('shipoopya'),
				ArgList = [DefaultOffset, CaseCount, CaseOffsets],
				((Path = 0) ->
					Offset = DefaultOffset
				;
					nth(Path, CaseOffsets, Offset)
				),
				NextIC is InstrCount,
				seek_jump_target(Offset, NextIC, RInsList, NextIC, NIC),
				TempPathInfo =.. [path_info, MethodNum, NIC, 0]
			)
		;
			seek_path_once(path_info(MethodNum,InstrCount,Path),TempPathInfo)
		),
		TempLength is OldLength + 1,
		hint_rewritten_seek(TempPathInfo, NewPathInfo, RMETH, MarkedList, TempLength, RLENGTH)
	).

request_hint(ABS,
	 	path_info(OMethodNum,OInstrCount,OP), 
		path_info(RMethodNum,RInstrCount,RP), 
		path_info(RMethodNum,RInstrCount,TRP), 
		hint(NEWABS,OLENGTH,RLENGTH)) :-

			%	((OMethodNum=835, OInstrCount=128) -> spy(break_me), break_me ; true),

	%format('In Request_hint, OInstrCount is ~w, RInstrCount is ~w~n~n',[OInstrCount,RInstrCount]),
	ABS =.. [abs_state,OState,RState,ConstraintList],
	
    	% Get the Global Variable Values
   	b_getval(uast, UntrustedAST),
   	b_getval(rast, RewrittenAST),

	% Step for the Untrusted AST

	abc_parser:getABC(method_bodies,UntrustedAST,UMethodBodies),
 	get_method3(OMethodNum,UMethodBodies,OMETH),
	OMETH =.. [method_body,_Method1,_MS1,_LC1,_ISD1,_MSD1,_CL1,OInsList,_EC1,_E1,_TC1,_T1],
	chop_list_until_nth(OInsList,OInstrCount,[_O-OI|_IList]),
	
	get_head_args(OI,OH,ArgList),
	(is_non_sequential(OH) -> 
		
		((OH \= lookupswitch) ->
			(ArgList = [OOffset],
			seek_jump_path(path_info(OMethodNum,OInstrCount,OP),ONewPathInfo,OOffset,OMETH)),
			TRP = RP,
			FoundLUS is 0
		;
			ArgList = [DefaultOffset, CaseCount, CaseOffsets],
			((OP = 0) ->
				OOffset = DefaultOffset,
				TRP = 1
			;
				nth(Path, CaseOffsets, OOffset),
				TRP = RP
			),
			NextIC is OInstrCount,
			seek_jump_target(OOffset, NextIC, OInsList, NextIC, NIC),
			%trace,
			ONewPathInfo =.. [path_info, MethodNum, NIC, 0],
			FoundLUS is 1

		)
	;
		seek_path_once(path_info(OMethodNum,OInstrCount,OP),ONewPathInfo),
		TRP = RP,
		FoundLUS is 0
	),






	%	hint_original_seek(path_info(OMethodNum,OInstrCount,OP),_NPIO,UntrustedAST),
	OLENGTH is 1,

	((FoundLUS = 1) ->
		((OP = 0) ->
			RLENGTH is 4
		;
			RLENGTH is (7+(3*OP))
		)
	;
		RLENGTH is 1
	),

	%abc_parser:getABC(method_bodies,RewrittenAST,RMethodBodies),
	%get_method3(RMethodNum,RMethodBodies,RMETH),

	%b_getval(markedinstrlist, MarkedLists),
	%get_marked_method2(RMethodNum, MarkedLists, MarkedList),

	%writeln(RMETH),
	%writeln('----'),
	%writeln(MarkedList),
	

	%hint_rewritten_seek(path_info(RMethodNum,RInstrCount,RP), _NPIR, RMETH, MarkedList, 0, RLENGTH),

	%EE1 =.. [env, SS1, OS1, RF1],
	%EE2 =.. [env, SS2, OS2, RF2],

	/* TODO: don't know if we really need the TempStates */

   	NewEE1 =.. [env, ScopeVar, OperandStackVar, RegFileVar],
   	NewEE2 =.. [env, ScopeVar, OperandStackVar, RegFileVar],

	NewOState =.. [state, HeapVar, [NewEE1], TraceVar, automaton(A1)],
    	NewRState =.. [state, HeapVar, [NewEE2], TraceVar, automaton(A1)],
    
	NEWABS = abs_state(NewOState,NewRState,ConstraintList).



is_non_sequential(ifeq).
is_non_sequential(iffalse).
is_non_sequential(ifge).
is_non_sequential(ifgt).
is_non_sequential(ifle).
is_non_sequential(iflt).
is_non_sequential(ifnge).
is_non_sequential(ifngt).
is_non_sequential(ifnle).
is_non_sequential(ifnlt).
is_non_sequential(ifne).
is_non_sequential(ifnge).
is_non_sequential(ifstricteq).
is_non_sequential(ifstrictne).
is_non_sequential(iftrue).
is_non_sequential(lookupswitch).

get_head_args(I,H,ArgList) :-
	I =.. [H,Arg1],
	ArgList = [Arg1].
get_head_args(I,H,ArgList) :-
	I =.. [H],
	ArgList = [].
get_head_args(I,H,ArgList) :-
	I =.. [H,Arg1,Arg2],
	ArgList = [Arg1,Arg2].
get_head_args(I,H,ArgList) :-
	I =.. [H,Arg1,Arg2,Arg3],
	ArgList = [Arg1,Arg2,Arg3].

seek_jump_target(N, NIC, OInsList, CC, CC) :-

	nth0(NIC, OInsList, Ins1),
	nth0(CC, OInsList, Ins2),
	Ins1 = (L1 - _I1),
	Ins2 = (L2 - _I2),
	N is (L2-L1).

seek_jump_target(N, NIC, OInsList, CC, FinalC) :-

	nth0(NIC, OInsList, Ins1),
	nth0(CC, OInsList, Ins2),
	Ins1 = (L1 - _I1),
	Ins2 = (L2 - _I2),

	( (N >= 0) ->
		NextCC is (CC+1)
	;
		NextCC is (CC-1)
	),

	seek_jump_target(N, NIC, OInsList, NextCC, FinalC).

	
seek_jump_path(PI, NPI, Offset, Meth) :-
	PI =.. [path_info, OMN, OIC, PIP],
	Mask is (PIP /\ 1),
	NewPIP is (PIP >> 1),

	( (Mask = 1) ->

		% Do the branch
		%abc_parser:getABC(method_bodies, AST, Methods),
		%nth0(OMN, Methods, Meth),
		Meth =.. [method_body,_Method1,_MS1,_LC1,_ISD1,_MSD1,_CL1,OInsList,_EC1,_E1,_TC1,_T1],
		NextIC is (OIC+1),
		seek_jump_target(Offset, NextIC, OInsList, NextIC, NIC),

		NPI =.. [path_info, OMN, NIC, NewPIP]
	;
		% Don't do the branch
		NewNIC is (OIC+1),
		NPI =.. [path_info, OMN, NewNIC, NewPIP]
	).
	
seek_path_once(PI,NPI) :-
	PI =.. [path_info,MethodNum, InstrCount, OP],
	NextInstrCount is (InstrCount+1),
	NPI =.. [path_info,MethodNum, NextInstrCount, OP].

symbolic_values(Value,[Value|R]) :- symbolic_values(Value,R).
symbolic_values(Value,[]).

break_me.

